#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define ARGC_SIZE 32
#define LINE_SIZE 1024
#define DELIM " "
#define EXIT_CODE 99

int quit = 0;
int last_code = 0;
extern char** environ;
char CommandLine[LINE_SIZE];
char* argv[ARGC_SIZE];
char pwd[LINE_SIZE];
char myenv[LINE_SIZE];

//获取用户名
const char* GetUserName()
{
  return getenv("USER");
}

//获取主机名
const char* GetHostName()
{
  return getenv("HOSTNAME");
}

//获取当前路径
void GetPwd()
{
  getcwd(pwd, sizeof(pwd));
}

void Interact(char* cl, int size)
{
  GetPwd();
  printf(LEFT"%s@%s %s"RIGHT LABLE" ", GetUserName(), GetHostName(), pwd);

  char* s = fgets(cl, size, stdin);
  //这里s无论如何都不可能为空，
  //因为什么都不输入都至少有一个回车，
  //所以空就是出错了。
  assert(s);
  (void)s;

  //把输入的回车去掉
  //"ls -a\n\0" -> "ls -a\0\0"
  cl[strlen(cl) - 1] = '\0';
}

int SplitString(char* cl, char* argv[])
{
  int i = 0;
  //CommandLine -> "ls -a -l\0" -> "ls" "-a" "-l"
  argv[i++] = strtok(cl, DELIM);
  while(argv[i++] = strtok(NULL, DELIM));
  return i - 1;
}

void NormalExcute(char* argv[])
{
  pid_t id = fork();
  if(id < 0)
  {
    perror("fork");
    return;
  }
  else if(id == 0)
  {
    //子进程执行命令
    execvpe(argv[0], argv, environ);
    exit(EXIT_CODE);
  }
  else
  {
    int status = 0;
    pid_t wid = waitpid(id, &status, 0);
    if(wid == id)
    {
      last_code = WEXITSTATUS(status);
    }
  }
}

int BuildCommand(char* argv[], int argc)
{
  //cd内建命令
  if(argc == 2 && strcmp(argv[0], "cd") == 0)
  {
    //修改当前目录
    chdir(argv[1]);

    //修改PWD环境变量
    GetPwd();
    sprintf(getenv("PWD"), "%s", pwd);

    return 1;
  }
  //export内建命令
  else if(argc == 2 && strcmp(argv[0], "export") == 0)
  {
    strcpy(myenv, argv[1]);
    putenv(myenv);

    return 1;
  }
  //echo内建命令
  else if(argc == 2 && strcmp(argv[0], "echo") == 0)
  {
    if(strcmp(argv[1], "$?") == 0)
    {
      printf("%d\n", last_code);
      last_code = 0;
    }
    else if(*argv[1] == '$')
    {
      char* val = getenv(argv[1] + 1);
      if(val)
      {
        printf("%s\n", val);
      }
    }
    else 
    {
      printf("%s\n", argv[1]);
    }

    return 1;
  }
  
  //给ls加颜色
  if(strcmp(argv[0], "ls") == 0)
  {
    argv[argc++] = "--color";
    argv[argc] = NULL;
  }

  return 0; 
}

int main()
{

  while(!quit)
  {
    //读取命令
    Interact(CommandLine, sizeof(CommandLine));

    //分析命令
    int argc = SplitString(CommandLine, argv);
    if(argc == 0)
    {
      continue;
    }

    //内建命令判断
    int n = BuildCommand(argv, argc);

    //执行普通命令
    if(!n)
    {
      NormalExcute(argv);
    }
  }

  return 0;
}
